#include "main.h"

meter_var_t mvar;

store_t defaults1 = {							//默认参数
					.low_volt = 4500,			//低压报警mV
					.over_curt = 54000,			//电流上限报警mA
					.over_temp = 50,			//温度报警℃
					.res = 3000,					//采样电阻,单位:纳欧，1毫欧=1000纳欧
					.MAXcurrent = 50000,			//最大电流单位:mA
					.main = 0,					//菜单界面光标位置
					.rotate = 1,				//屏幕方向
					.contrast = contrastMid,	//屏幕亮度

					//INA228_配置寄存器
					.Config_RST=0,				//ina228复位0=不复位 1=复位.
					.Config_RSTACC=0,			//清空累计寄存器0=不清空 1=清空.
					.Config_CONVDLY=0,			//以2ms的步长设置初始ADC转换的延迟.范围:0-255 = 0-510ms.
					.Config_TEMPCOMP=1,			//启用外部分流器的温度补偿0=禁用 1=启用.
					.Config_ADCRANGE=0,			//电流采样量程选择.0=±163.84mV，1=±40.96mV

					//INA228片上ADC配置寄存器
					.ADC_ADCMode=15,				//ADC触发模式，范围0-15.
					.ADC_VBUSCT=4,				//设置总线电压测量的转换时间.	范围:0=50µs， 1=84µs， 2=150µs， 3=280µs， 4=540µs， 5=1052µs， 6=2074µs， 7=4120µs
					.ADC_VSHCT=4,				//设置分流电压测量的转换时间.	范围0-7	:时间同上
					.ADC_VTCT=0,				//设置温度测量的转换时间.	范围0-7	:时间同上
					.ADC_ADCAVG=5,				//选择 ADC平均采样.平均值计算设置适用于所有有效输入。当 >0h 时,将在平均值计算完成后更新输出寄存器.
												//			范围:	0=1， 1=4， 2=16， 3=64， 4=128， 5=256， 6=512， 7=1024

					.Config_TEMPCOMP_PPM=25,	//采样电阻温度补偿系数,以+25°C为基准进行计算.单位：ppm/℃ 范围:0-16383	共14bit.
					};


history_count defaults2 = {							//默认参数
					.Count_Max_mA=0,
					.Count_Max_mW=0,
					.Count_mAh=0,
					.Count_mWh=0,
					};

char* time_str(void) {			//输出时间，格式00:00:00
	time_t now;
	struct tm tm;
	static char str[16] = { 0 };

	time(&now);
	localtime_r(&now, &tm);
	snprintf(str, sizeof(str), "%02d:%02d:%02d", tm.tm_hour,tm.tm_min, tm.tm_sec);

	return str;
}

char* voltage_str(int mV) {		//输出电压，格式00：000V
	static char S[16] = { 0 };
	snprintf(S, sizeof(S), "%06.3fV", (float) mV / 1000);
	return S;
}

char* current_str(int mA) {		//输出取绝对值电流，格式00：000A
	mA=abs(mA);
	static char S[16] = { 0 };
	snprintf(S, sizeof(S), "%06.3fA", (float) mA / 1000);
	return S;
}

/*	char* charge_str(int mAh) {		//输出电流，格式00：000Ah
		static char S[16] = { 0 };
		if(mAh>=10000||mAh<=-10000){
		snprintf(S, sizeof(S), "%05.2fAh", (double) mAh / 1000);
		}else{
			snprintf(S, sizeof(S), "%05.3fAh", (double) mAh / 1000);
		}
		return S;
	}*/

char* charge_str(int32_t mAh) {		//输出取绝对值毫安时，格式0000000000：000Ah
	mAh=abs(mAh);
	static char S[16] = { 0 };
	snprintf(S, sizeof(S), "%07.3f", (float) mAh / 1000);
	return S;
}

char* power_str(float mW)										//输出功率，自动切换挡位
{
	static char S[16] = { 0 };
	mW=fabsf(mW);
	if (mW >= 1000000) {									//1000.0W+
		snprintf(S, sizeof(S), "%.1fW", mW / 1000);
	} else if (mW >= 100000) {								//100.00W+
		snprintf(S, sizeof(S), "%.2fW", mW / 1000);
	} else if (mW >= 10000) {								//10.000W+
		snprintf(S, sizeof(S), "%.3fW", mW / 1000);
	} else {												//1.0000W+
		snprintf(S, sizeof(S), "%.4fW", mW / 1000);
	}
	return S;
}

char* power_str2(float mW)								//主页1功率显示单位切换
{
	static char S[16] = { 0 };
	mW=fabsf(mW);
	if (mW >= 1000000) {									//1000.0 W+
		snprintf(S, sizeof(S), "%.1fW", mW / 1000);
	} else if (mW >= 100000) {								//100.00 W+
		snprintf(S, sizeof(S), "%.2fW", mW / 1000);
	} else if (mW >= 10000) {								//10.000 W+
		snprintf(S, sizeof(S), "%.3fW", mW / 1000);
	} else {												//0.0000 W+
		snprintf(S, sizeof(S), "%.4fW", mW / 1000);
	}
	return S;
}

char* elec_str2(int32_t mWh) {										//主页瓦时单位切换
	mWh=abs(mWh);
	static char S[16] = { 0 };
	snprintf(S, sizeof(S), "%07.3f", (float) mWh / 1000);
	return S;
}

char* current_state_str(float mA) {										//电流方向显示
	static char S[16] = { 0 };
	if (mA >= 1) {
		if (mvar.store.rotate == 1) {
			snprintf(S, sizeof(S), ">>>");
		} else {
			snprintf(S, sizeof(S), "<<<");
		}
	} else if (mA <= -1) {
		if (mvar.store.rotate == 1) {
			snprintf(S, sizeof(S), "<<<");
		} else {
			snprintf(S, sizeof(S), ">>>");
		}
	} else {
		snprintf(S, sizeof(S), "===");
	}
	return S;
}

#ifdef CONFIG_IDF_TARGET_ESP32C3
char* temp_str(void) {
	static char S[16] = { 0 };
	char V[16] = { 0 };
	snprintf(V, sizeof(V), "%d C", (int) mvar.msr.temp);
	snprintf(S, sizeof(S), "%5s", V);
	return S;
}
#endif

void show_box(int x1, int y1, int x2, int y2) {
	oled_draw_line(x1, y1, x2, y1);
	oled_draw_line(x1, y2, x2, y2);
	oled_draw_line(x1, y1, x1, y2);
	oled_draw_line(x2, y1, x2, y2);

	oled_draw_line(x1 + 1, y1 + 1, x2 - 1, y1 + 1);
	oled_draw_line(x1 + 1, y2 - 1, x2 - 1, y2 - 1);
	oled_draw_line(x1 + 1, y1 + 1, x1, y2 - 1);
	oled_draw_line(x2 - 1, y1 + 1, x2 - 1, y2 - 1);
	for (int x = x1 + 2; x < x2 - 1; x++) {
		for (int y = y1 + 2; y < y2 - 1; y++) {
			oled_clear_dot(x, y);
		}
	}
}

char* resistor_str(void) {				//等效负载电阻，与温度显示共用一个位置，esp32c3显示温度不显示这个
	static char S[16] = { 0 };
	char str[16] = { 0 };
	int R = mvar.msr.mV * 1000 / mvar.msr.mA;

	if (R < 1000) {
		snprintf(str, sizeof(str), "%dm", R);
	} else if (R < 10000) {
		snprintf(str, sizeof(str), "%.2f", (double) R / 1000);
	} else if (R < 100000) {
		snprintf(str, sizeof(str), "%.1f", (double) R / 1000);
	} else if (R < 1000000) {
		snprintf(str, sizeof(str), "%d", R / 1000);
	} else if (R < 10000000) {
		snprintf(str, sizeof(str), "%.1fK", (double) R / 1000000);
	} else if (R < 1000000000) {
		snprintf(str, sizeof(str), "%dK", R / 1000000);
	}
	snprintf(S, sizeof(S), "%4s", str);
	return S;
}

void view_show_main(void) {												//main显示函数

	oled_clear();
	oled_show_string(0, 0, voltage_str(mvar.msr.mV), FontSize_12x24);	//显示电压
	oled_show_string(0, 25, current_str(mvar.msr.mA), FontSize_12x24);	//显示电流
	oled_show_string(0, 55, time_str(), FontSize_6x8);					//显示时间

#ifdef CONFIG_IDF_TARGET_ESP32C3
	oled_show_string(51, 55, temp_str(), FontSize_6x8);					//显示温度
	oled_show_char_extend(69, 55, 0);									//显示负载等效电阻
#else
    oled_show_string(50, 53, resistor_str(), FontSize_6x8);
    oled_show_char_extend(74, 53, 4);
#endif

	oled_draw_dot_line(0, 50, 85, 50);	//时间与温度划线隔离
	oled_draw_dot_line(53, 50, 53, 63);	//中间的竖线

	oled_draw_dot_line(85, 0, 85, 63);	//左右分离线

	oled_show_string(86, 0, power_str2(mvar.msr.mW), FontSize_6x8);		//显示功率
	oled_draw_dot_line(86, 9, 127, 9);	//分离线

	oled_show_string(86, 12, elec_str2(mvar.msr.mWH+mvar.msr.mWh_tmp), FontSize_6x8);//显示毫安时
	oled_show_string(88, 24,"Ah", FontSize_6x8);
	oled_show_string(113, 24,"Wh", FontSize_6x8);
	oled_draw_dot_line(86, 21, 107, 21);
	oled_draw_dot_line(108, 21, 108, 33);
	oled_draw_dot_line(108, 33, 127, 33);
	oled_show_string(86, 36, charge_str(mvar.msr.mAH+mvar.msr.mAh_tmp), FontSize_6x8);//显示瓦时
	oled_draw_dot_line(86, 45, 127, 45);//分离线

	oled_show_string(94, 47,current_state_str(mvar.msr.mA), FontSize_8x16);			//显示电流方向

}

void view_show_main2(void) {
	oled_clear();
	oled_show_text(0, 5, "voltage");
	oled_show_text(0, 25, "current");
	oled_show_text(0, 45, "power");
	oled_show_string(32, 5, ":", FontSize_8x16);
	oled_show_string(32, 25, ":", FontSize_8x16);
	oled_show_string(32, 45, ":", FontSize_8x16);
	oled_show_string(39, 40, power_str(mvar.msr.mW), FontSize_12x24);
	oled_show_string(39, 20, current_str(mvar.msr.mA), FontSize_12x24);
	oled_show_string(39, 0, voltage_str(mvar.msr.mV), FontSize_12x24);
}
void view_show_main3(void) {
	oled_clear();
	oled_show_text(29, 0, "max_info");
	oled_show_text(0, 25, "current");
	oled_show_text(0, 45, "power");
	oled_show_string(34, 25, ":", FontSize_8x16);
	oled_show_string(34, 45, ":", FontSize_8x16);
	oled_show_string(42, 40, power_str(mvar.msr.max_mW), FontSize_12x24);
	oled_show_string(42, 20, current_str(mvar.msr.max_mA), FontSize_12x24);

}

//量程范围定义
const static struct {
	int max;    //最大量程
	int div;    //每格值
	int base;   //基数
} rangeTab[] = { { 50, 10, 1 }, { 100, 20, 1 }, { 250, 50, 1 }, { 500, 100, 1 },
		{ 1000, 200, 1 }, { 2000, 400, 1 }, { 5, 1, 1000 }, { 10, 2, 1000 }, {
				15, 3, 1000 }, { 20, 4, 1000 }, { 25, 5, 1000 },
		{ 30, 6, 1000 }, { 35, 7, 1000 }, { 40, 8, 1000 }, { 45, 9, 1000 }, {
				50, 10, 1000 }, { 60, 12, 1000 }, { 70, 14, 1000 } };

int timeDivList[] = { 1, 5, 10, 60, 120 };

#define xDivNum 26   //X轴格数
#define yDivNum 40   //Y轴格数

void curt_curve_show(void) {
	int i;
	int div = timeDivList[mvar.timeDiv];
	char S[32] = { 0 };

	oled_clear();
	//X轴
	oled_draw_line(21, 51, 127, 51);
	oled_draw_line(124, 49, 127, 51);
	oled_draw_line(124, 53, 127, 51);

	//Y轴
	oled_draw_line(21, 0, 21, 51);
	oled_draw_line(21, 0, 19, 3);
	oled_draw_line(21, 0, 23, 3);

	//X坐标
	for (int i = 21; i < 124; i += 4) {
		oled_draw_line(i, 52, i, 53);
	}
	int div_t, all_t, all;
	char *div_u, *all_u;
	if (div < 60) {
		div_t = div;
		div_u = "s";
	} else {
		div_t = div / 60;
		div_u = "m";
	}
	all = div * xDivNum;
	if (all < 60) {
		all_t = all;
		all_u = "s";
	} else {
		all_t = all / 60;
		all_u = "m";
	}
	int len = snprintf(S, sizeof(S), "%d%s/div t:%d%s", div_t, div_u, all_t,
			all_u);

	oled_show_string(127 - len * 6, 56, S, FontSize_6x8);

	int n = 0;
	int rid = 0;
	int max = 0, min = -1;
	int start;
	if (mvar.history.len > xDivNum * div) {
		start = mvar.history.len - xDivNum * div;
	} else {
		start = mvar.history.len - mvar.history.len / div * div;
	}

	for (int i = start; i < mvar.history.len; i += div) {
		int val = 0;
		for (int j = 0; j < div; j++) {
			val += mvar.history.list[i + j];
		}
		val /= div;
		if (val > max) {
			max = val;
		}
		if (min == -1 || val < min) {
			min = val;
		}
	}

	//量程
	for (int i = 0; i < ASIZE(rangeTab); i++) {
		if ((rangeTab[i].max * rangeTab[i].base) > max) {
			rid = i;
			break;
		}
	}

	//显示最大最小值
	len = snprintf(S, sizeof(S), "%s", current_str(max));
	oled_show_char_extend(37, 0, 1);
	oled_show_string(43, 0, S, FontSize_6x8);
	oled_show_char_extend(49 + len * 6, 0, 2);
	snprintf(S, sizeof(S), "%s", current_str(min));
	oled_show_string(55 + len * 6, 0, S, FontSize_6x8);

	//Y坐标
	for (int i = 51; i > 0 && n <= 5; i -= 8, n++) {
		oled_draw_line(19, i, 20, i);
		if (rangeTab[rid].max >= 1000) {
			snprintf(S, sizeof(S), "%.1f",
					(double) (rangeTab[rid].div * n) / 1000);
		} else {
			snprintf(S, sizeof(S), "%3d", rangeTab[rid].div * n);
		}
		oled_show_string(0, i - 4, S, FontSize_6x8);
	}
	snprintf(S, sizeof(S), "%3s",
			(rangeTab[rid].base == 1 && rangeTab[rid].max < 1000) ? "mA" : "A");
	oled_show_string(0, 55, S, FontSize_6x8);

	int last = 0;
	for (i = start, n = 0; i < mvar.history.len && n < xDivNum; i += div, n++) {
		int val = 0;
		for (int j = 0; j < div; j++) {
			val += mvar.history.list[i + j];
		}
		val /= div;
		val = yDivNum
				- (val * yDivNum / (rangeTab[rid].max * rangeTab[rid].base));
		val += 11;
		if (n == 0) {
			last = val;
			continue;
		} else {
			oled_draw_line(21 + (n - 1) * 4, last, 21 + n * 4, val);
			last = val;
		}
	}
}

void show_alert(void) {											//显示报警
	char *type = NULL;
	static int alert = 0;

	if (mvar.msr.mV < mvar.store.low_volt) {
		type = "low_volt";
	} else if (mvar.msr.mA > mvar.store.over_curt) {
		type = "over_curt";
	} else if (mvar.msr.temp > mvar.store.over_temp) {
		type = "over_temp";
	}

	if (!type) {
		return;
	}

	if (mvar.view != view_show_main && mvar.view != view_show_main2
			&& mvar.view != curt_curve_show) {
		return;
	}

	if (alert < 3) {
		alert++;
		show_box(24, 16, 112, 48);
		oled_show_text(32, 24, type);
		//buzzer_set(buzzerShort);
	} else if (alert < 6) {
		alert++;
	} else {
		alert = 0;
	}
}

static view_show main_views[] = { view_show_main, view_show_main2,view_show_main3 };

//电量统计，1秒执行一次
void elec_timer_fun(unsigned long data) {

	mvar.history.list[mvar.history.len++] = abs(mvar.msr.mA);
	if (mvar.history.len == HISTORY_MAX) {
		memmove(mvar.history.list, mvar.history.list + HISTORY_DROP,
				(HISTORY_MAX - HISTORY_DROP) * 4);
		mvar.history.len -= HISTORY_DROP;
	}
	mod_timer(&mvar.elec_timer, jiffies + HZ);
}

void key_fun_low_volt(int event) {
	switch (event) {
	case keyLeftShort:
		if (!mvar.seting) {
			if (mvar.set_idx > 0) {
				mvar.set_idx--;
			}
		} else {
			int dec = pow(10, 4 - mvar.set_idx);
			if (mvar.store.low_volt >= dec) {
				mvar.store.low_volt -= dec;
			}
		}
		break;
	case keyRightShort:
		if (!mvar.seting) {
			if (mvar.set_idx < 3) {
				mvar.set_idx++;
			}
		} else {
			int dec = pow(10, 4 - mvar.set_idx);
			if (mvar.store.low_volt <= 85000-dec) {
				mvar.store.low_volt += dec;
			}
		}
		break;
	case keySetShort:
		mvar.seting = !mvar.seting;
		break;
	case keySetLong:
		mvar.view = view_show_menu;
		save();
		break;
	default:
		break;
	}
}

void key_fun_over_curt(int event) {
	switch (event) {
	case keyLeftShort:
		if (!mvar.seting) {
			if (mvar.set_idx > 0) {
				mvar.set_idx--;
			}
		} else {
			int dec = pow(10, 4 - mvar.set_idx);
			if (mvar.store.over_curt >= (dec+10)) {
				mvar.store.over_curt -= dec;
			}
		}
		break;
	case keyRightShort:
		if (!mvar.seting) {
			if (mvar.set_idx < 3) {
				mvar.set_idx++;
			}
		} else {
			int dec = pow(10, 4 - mvar.set_idx);
			if (mvar.store.over_curt <= 99990-dec) {
				mvar.store.over_curt += dec;
			}
		}
		break;
	case keySetShort:
		mvar.seting = !mvar.seting;
		break;
	case keySetLong:
		mvar.view = view_show_menu;
		save();
		break;
	default:
		break;
	}
}

#ifdef CONFIG_IDF_TARGET_ESP32C3
void key_fun_over_temp(int event) {
	switch (event) {
	case keyLeftShort:
		if (mvar.store.over_temp > 20) {
			mvar.store.over_temp--;
		}
		break;
	case keyRightShort:
		if (mvar.store.over_temp < 80) {
			mvar.store.over_temp++;
		}
		break;
	case keyLeftLong:
		if (mvar.store.over_temp >= 30) {
			mvar.store.over_temp-=10;
		}
		break;
	case keyRightLong:
		if (mvar.store.over_temp <= 70) {
			mvar.store.over_temp+=10;
		}
		break;

	case keySetShort:
	case keySetLong:
		mvar.view = view_show_menu;
		save();
		break;
	default:
		break;
	}
}
#endif

void key_fun_contrast_set(int event) {
	switch (event) {
	case keyLeftShort:
		if (mvar.store.contrast > contrastLow) {
			mvar.store.contrast--;
		}
		oled_contrast(mvar.store.contrast);
		break;
	case keyRightShort:
		if (mvar.store.contrast < contrastHigh) {
			mvar.store.contrast++;
		}
		oled_contrast(mvar.store.contrast);
		break;
	case keySetShort:
	case keySetLong:
		mvar.view = view_show_menu;
		save();
		break;
	default:
		break;
	}
}

void key_fun_range_set(int event) {			//最大量程设置，根据预设的采样电阻值显示档位，暂时没有实现实际功能
	switch (event) {
	case keyLeftShort:
		if(mvar.store.MAXcurrent>=2000){
			mvar.store.MAXcurrent-=1000;
		}
		break;
	case keyRightShort:
		if(mvar.store.MAXcurrent<=127000){
			mvar.store.MAXcurrent+=1000;
		}
		break;
	case keyLeftLong:
		if(mvar.store.MAXcurrent>=11000){
			mvar.store.MAXcurrent-=10000;
		}
		break;
	case keyRightLong:
		if(mvar.store.MAXcurrent<=118000){
			mvar.store.MAXcurrent+=10000;
		}
		break;

	case keySetShort:
	case keySetLong:
		mvar.view = view_show_menu;
		save();
		ina228_set_shunt_cal(0);
		break;
	default:
		break;
	}
}

void key_fun_res_set(int event){
	switch (event) {
	case keyLeftShort:
		if (!mvar.seting) {
			if (mvar.set_idx > 0) {
				mvar.set_idx--;
			}
		} else {
			int dec = pow(10, 4 - mvar.set_idx);
			if (mvar.store.res >= (dec+10)){
				mvar.store.res -= dec;
			}
		}
		break;
	case keyRightShort:
		if (!mvar.seting) {
			if (mvar.set_idx < 3) {
				mvar.set_idx++;
			}
		} else {
			int dec = pow(10, 4 - mvar.set_idx);
			if (mvar.store.res <= 99990-dec) {
				mvar.store.res += dec;
			}
		}
		break;
	case keySetShort:
		mvar.seting = !mvar.seting;
		break;
	case keySetLong:
		mvar.view = view_show_menu;
		save();
		break;
	default:
		break;
	}
}

void over_curt_set(void) {
	char S[32] = { 0 };
	int x = 0;

	oled_clear();
	oled_show_text(32, 8, "over_curt");
	if (mvar.store.over_curt >= 10000) {
		snprintf(S, sizeof(S), "[%.2fA]", (double) mvar.store.over_curt / 1000);
	} else {
		snprintf(S, sizeof(S), "[0%.2fA]",
				(double) mvar.store.over_curt / 1000);
	}
	if (mvar.set_idx >= 2) {
		x = mvar.set_idx + 2;
	} else {
		x = mvar.set_idx + 1;
	}
	if (mvar.seting) {
		static int blink = 0;
		if (blink) {
			S[x] = ' ';
		}
		blink = !blink;
	}
	oled_show_string(40, 26, S, FontSize_8x16);
	oled_draw_line(40 + x * 8, 41, 40 + x * 8 + 7, 41);
}

#ifdef CONFIG_IDF_TARGET_ESP32C3
void over_temp_set(void) {
	char S[32] = { 0 };

	oled_clear();
	oled_show_text(32, 8, "over_temp");
	snprintf(S, sizeof(S), "[ %d ]", mvar.store.over_temp);
	oled_show_string(44, 26, S, FontSize_8x16);
}
#endif

void low_volt_set(void) {
	char S[32] = { 0 };
	int x = 0;

	oled_clear();
	oled_show_text(32, 8, "low_volt");
	snprintf(S, sizeof(S), "[%05.2fV]", (double) mvar.store.low_volt / 1000);
	if (mvar.set_idx >= 2) {
		x = mvar.set_idx + 2;
	} else {
		x = mvar.set_idx + 1;
	}
	if (mvar.seting) {
		static int blink = 0;
		if (blink) {
			S[x] = ' ';
		}
		blink = !blink;
	}
	oled_show_string(32, 26, S, FontSize_8x16);
	oled_draw_line(32 + x * 8, 41, 32 + x * 8 + 7, 41);
}

void contrast_set(void) {
	oled_clear();
	oled_show_text(32, 8, "contrast");
	if (mvar.store.contrast == contrastHigh) {
		oled_show_text(56, 30, "high");
	} else if (mvar.store.contrast == contrastMid) {
		oled_show_text(56, 30, "mid");
	} else if (mvar.store.contrast == contrastLow) {
		oled_show_text(56, 30, "low");
	}
}

void range_set(void) {
	char S[32] = { 0 };

	oled_clear();
	oled_show_text(32, 8, "range_set");
	snprintf(S, sizeof(S), "[ %02ldA ]", mvar.store.MAXcurrent/1000);
	oled_show_string(40, 26, S, FontSize_8x16);
}
void res_set(void){
	char S[32] = { 0 };
	int x = 0;

	oled_clear();
	oled_show_text(40, 8, "res_set");
	snprintf(S, sizeof(S), "[ %05.2fm  ]", (double) mvar.store.res / 1000);
	if (mvar.set_idx >= 2) {
		x = mvar.set_idx + 3;
	} else {
		x = mvar.set_idx + 2;
	}
	if (mvar.seting) {
		static int blink = 0;
		if (blink) {
			S[x] = ' ';
		}
		blink = !blink;
	}
	oled_show_string(24, 26, S, FontSize_8x16);
	oled_show_char_extend_8x16(88, 26, 0);
	oled_draw_line(24 + x * 8, 41, 24 + x * 8 + 7, 41);
}
void config_info(void){										//显示参数的界面
	char S[32] = { 0 };
	oled_clear();
	oled_show_text(29, 0, "config_info");
	snprintf(S, sizeof(S), "[res      =%-6lduR ]", mvar.store.res);
	oled_show_string(0,16,S,FontSize_6x8);
	snprintf(S, sizeof(S), "[max_c    =%-6ldmA ]", mvar.store.MAXcurrent);
	oled_show_string(0,24,S,FontSize_6x8);
	if(mvar.store.Config_TEMPCOMP==1){
		snprintf(S, sizeof(S), "[TEMP COMP=%-5dPPM ]", mvar.store.Config_TEMPCOMP_PPM);
		oled_show_string(0,32,S,FontSize_6x8);
	}else{
		oled_show_string(0,32,"[TEMP COMP=OFF      ]",FontSize_6x8);
	}
	int t[8]={1,4,16,64,128,256,512,1024};
	snprintf(S, sizeof(S), "[ADCAVG   =%-8d ]", t[mvar.store.ADC_ADCAVG]);
	oled_show_string(0,40,S,FontSize_6x8);
	int tt[8]={50,84,150,280,540,1052,2074,4120};
	snprintf(S, sizeof(S), "[VBUSCT   =%-6dus ]", tt[mvar.store.ADC_VBUSCT]);
	oled_show_string(0,48,S,FontSize_6x8);
	snprintf(S, sizeof(S), "[VSHCT    =%-6dus ]", tt[mvar.store.ADC_VSHCT]);
	oled_show_string(0,56,S,FontSize_6x8);



}

void def_set(void) {										//恢复默认设置，校准值不会被重置
	oled_clear();
	oled_show_text(8, 24, "def_ok");
	mvar.store = defaults1;
	save();
	vTaskDelay(500);
	mvar.view = view_show_menu;
}

const int volt_cal_point[] = { 5000, 10000, 15000, 20000 }; //mV						电压分档校准档位
const int curt_cal_point[] = { 1000, 2000, 5000, 10000, 20000, 50000 }; //mA			电流分档校准档位

void volt_cal(void) {
	char S[32] = { 0 };

	oled_clear();

	oled_show_text(20, 10, "cal_dot");
	snprintf(S, sizeof(S), "<%dV>", volt_cal_point[mvar.cal_point] / 1000);
	oled_show_string(76, 10, S, FontSize_8x16);

	oled_show_text(20, 30, "voltage");
	oled_show_string(60, 30, voltage_str(mvar.msr.mV), FontSize_8x16);

	float cal = mvar.cal.volt[mvar.cal_point].val;
	if (cal > 1.0) {
		snprintf(S, sizeof(S), "+%f", cal - 1.0);
	} else {
		snprintf(S, sizeof(S), "-%f", 1.0 - cal);
	}
	oled_show_string(40, 50, S, FontSize_6x8);
}

void curt_cal(void) {
	char S[32] = { 0 };

	oled_clear();

	oled_show_text(20, 10, "cal_dot");
	snprintf(S, sizeof(S), "<%dA>", curt_cal_point[mvar.cal_point] / 1000);
	oled_show_string(76, 10, S, FontSize_8x16);

	oled_show_text(20, 30, "current");
	oled_show_string(60, 30, current_str(mvar.msr.mA), FontSize_8x16);

	float cal = mvar.cal.curt[mvar.cal_point].val;
	if (cal > 1.0) {
		snprintf(S, sizeof(S), "+%f", cal - 1.0);
	} else {
		snprintf(S, sizeof(S), "-%f", 1.0 - cal);
	}
	oled_show_string(40, 50, S, FontSize_6x8);
}

void zero_cal(void) {
	char S[32] = { 0 };

	oled_clear();

	oled_show_text(32, 8, "zero_cal");
	snprintf(S, sizeof(S), "<%d>", mvar.cal.zero);
	oled_show_string(48, 26, S, FontSize_8x16);
	oled_show_string(48, 42, current_str(mvar.msr.raw_mA), FontSize_8x16);
}

static struct {
	char *name;
	menu_fun fun;
} menus[] = {
		{ "curt_curve", curt_curve_show },
		{ "low_volt", low_volt_set },
		{ "over_curt", over_curt_set },
#ifdef CONFIG_IDF_TARGET_ESP32C3
		{ "over_temp", over_temp_set },
#endif
		{ "range_set", range_set },
		{"res_set",res_set},
		{ "contrast", contrast_set },
//		{ "curt_cal",curt_cal },		//校准只能校准屏幕显示的内容，实际容量，功率的计算都是ina228内部完成，而ina228只能校准电流，所以大可不必。如有必要，可以调整采样电阻值来校准误差
//		{ "volt_cal", volt_cal },
//		{ "zero_cal", zero_cal },
		{ "config_info", config_info },
		{ "def_set", def_set },
			};

void key_fun_volt_cal(int event) {										//电压校准
	switch (event) {
	case keyLeftShort:
		if (mvar.cal_point > 0) {
			mvar.cal_point--;
		}
		break;
	case keyRightShort:
		if (mvar.cal_point < ASIZE(mvar.cal.volt) - 1) {
			mvar.cal_point++;
		}
		break;
	case keySetShort:
		float cal = (float) volt_cal_point[mvar.cal_point]
				/ (float) mvar.msr.raw_mV;
		if (cal > 0.8 && cal < 1.2) {
			mvar.cal.volt[mvar.cal_point].raw = mvar.msr.raw_mV;
			mvar.cal.volt[mvar.cal_point].val = cal;
		}
		break;
	case keyLeftLong:												//左键长按清除校准参数
		for (int i = 0; i < ASIZE(mvar.cal.volt); i++)
		{
			mvar.cal.volt[i].val = 1.0;
		}
		save_cal();
		break;
	case keySetLong:
		save_cal();
		mvar.view = view_show_menu;
		break;
	default:
		break;
	}
}

void key_fun_curt_cal(int event) {										//电流校准
	switch (event) {
	case keyLeftShort:
		if (mvar.cal_point > 0) {
			mvar.cal_point--;
		}
		break;
	case keyRightShort:
		if (mvar.cal_point < ASIZE(mvar.cal.curt) - 1) {
			mvar.cal_point++;
		}
		break;
	case keySetShort:
		float cal = (float) curt_cal_point[mvar.cal_point]
				/ (float) mvar.msr.raw_mA;
		if (cal > 0.6 && cal < 1.4) {
			mvar.cal.curt[mvar.cal_point].raw = mvar.msr.raw_mA;
			mvar.cal.curt[mvar.cal_point].val = cal;
		}
		break;
	case keyLeftLong:												//左键长按清除校准参数
		for (int i = 0; i < ASIZE(mvar.cal.curt); i++)
		{
			mvar.cal.curt[i].val = 1.0;
		}
		save_cal();
		break;
	case keySetLong:
		save_cal();
		mvar.view = view_show_menu;
		break;
	default:
		break;
	}
}

void key_fun_zero_cal(int event) {
	switch (event) {
	case keyLeftShort:
		if (mvar.cal.zero > -50) {
			mvar.cal.zero--;
		}
		break;
	case keyRightShort:
		if (mvar.cal.zero < 50) {
			mvar.cal.zero++;
		}
		break;
	case keySetShort:
	case keySetLong:
		save_cal();
		mvar.view = view_show_menu;
		break;
	default:
		break;
	}
}
void key_fun_config_info(int event) {
	switch (event) {
	case keyLeftShort:
	case keyRightShort:
	case keySetShort:
	case keySetLong:
		mvar.view = view_show_menu;
		break;
	default:
		break;
	}
}
void key_fun_curt_curve(int event) {
	switch (event) {
	case keyLeftShort:
		if (mvar.timeDiv > 0) {
			mvar.timeDiv--;
		}
		break;
	case keyRightShort:
		if (mvar.timeDiv < ASIZE(timeDivList) - 1) {
			mvar.timeDiv++;
		}
		break;
	case keySetShort:
	case keySetLong:
		mvar.view = view_show_menu;
		break;
	default:
		break;
	}
}

void view_show_menu(void) {
	oled_clear();
	for (int i = 0; i < 4; i++) {
		oled_show_text(0, i * 16, menus[i + mvar.menuStart].name);
	}
	int row = mvar.menuIdx - mvar.menuStart;			//row是光标选中的选项在屏幕中位显示位置，应该是让光标所在项目反色显示的功能
	for (int i = 0; i < 128; i++) {
		GRAM[row * 2][i] = ~GRAM[row * 2][i];
		GRAM[row * 2 + 1][i] = ~GRAM[row * 2 + 1][i];
	}
}

void key_fun_menu(int event) {							//mvar.menuStart是控制翻页的，屏幕只能容纳4个选项，继续往下翻页，就修改开始显示的项目
	switch (event) {									//mvar.menuIdx是光标位置
	case keyLeftShort:
		if (mvar.menuIdx > 0) {
			mvar.menuIdx--;
			if (mvar.menuIdx < mvar.menuStart) {
				mvar.menuStart = mvar.menuIdx;
			}
		}
		break;
	case keyRightShort:
		if (mvar.menuIdx < ASIZE(menus) - 1) {
			mvar.menuIdx++;
			Printf("mvar.menuIdx:%d\n", mvar.menuIdx);
			if (mvar.menuIdx > mvar.menuStart + 3) {
				mvar.menuStart = mvar.menuIdx - 3;
				Printf("mvar.menuStart:%d\n", mvar.menuStart);
			}
		}
		break;
	case keySetShort:
		mvar.seting = 0;
		mvar.set_idx = 0;
		mvar.cal_point = 0;
		mvar.view = menus[mvar.menuIdx].fun;
		break;
	case keySetLong:
		mvar.view = main_views[0];
		break;
	default:
		break;
	}
}

void key_fun_main(int event) {									//主页1与主页2的按键处理函数
	switch (event) {
	case keyLeftShort:
		if (mvar.store.main < ASIZE(main_views) - 1) {
			mvar.store.main++;
		} else {
			mvar.store.main = 0;
		}
		mvar.view = main_views[mvar.store.main];
		save();
		break;
	case keyLeftLong:											//左键长按清零
		mvar.msr.mAh_tmp=0;
		mvar.msr.mWh_tmp=0;
		mvar.count.Count_mAh=0;
		mvar.count.Count_mWh=0;
		mvar.msr.max_mA=0;
		mvar.msr.max_mW=0;
		mvar.count.Count_Max_mA=0;
		mvar.count.Count_Max_mW=0;
		ina228_reset_acc(0);
		save_count();
		break;
	case keyRightShort:
		mvar.store.rotate = !mvar.store.rotate;
		oled_display_rotate(mvar.store.rotate);
		save();
		break;
	case keySetShort:
		mvar.menuIdx = 0;
		mvar.menuStart = 0;
		mvar.view = view_show_menu;
		break;
	default:
		break;
	}
}

void key_handler_fun(int event) {
	if (mvar.view == view_show_main || mvar.view == view_show_main2|| mvar.view == view_show_main3) {
		return key_fun_main(event);
	} else if (mvar.view == view_show_menu) {
		return key_fun_menu(event);
	} else if (mvar.view == curt_curve_show) {
		return key_fun_curt_curve(event);
	} else if (mvar.view == low_volt_set) {
		return key_fun_low_volt(event);
	} else if (mvar.view == over_curt_set) {
		return key_fun_over_curt(event);
	}
#ifdef CONFIG_IDF_TARGET_ESP32C3
	else if (mvar.view == over_temp_set) {
		return key_fun_over_temp(event);
	}
#endif
	else if (mvar.view == contrast_set) {
		return key_fun_contrast_set(event);
	} else if (mvar.view == range_set) {
		return key_fun_range_set(event);
	}else if(mvar.view==res_set){
	        return key_fun_res_set(event);
	} else if (mvar.view == volt_cal) {
		return key_fun_volt_cal(event);
	} else if (mvar.view == curt_cal) {
		return key_fun_curt_cal(event);
	} else if (mvar.view == zero_cal) {
		return key_fun_zero_cal(event);
	}else if (mvar.view == config_info) {
		return key_fun_config_info(event);
	}
}

void show_timer_fun(unsigned long data) {
	mvar.view();
	mod_timer(&mvar.show_timer, jiffies + 100);
}

int nvram_set_data(char *name, void *data, int len) {
	int ret = -1;
	nvs_handle_t nvram;
	esp_err_t err = nvs_open("nvram", NVS_READWRITE, &nvram);
	if (err != ESP_OK) {
		Printf("nvs_open:%s(%X)\n", esp_err_to_name(err), err);
		return -1;
	}

	err = nvs_set_blob(nvram, name, data, len);
	if (err != ESP_OK) {
		Printf("nvs_set_blob %s:%s(%X)\n", name, esp_err_to_name(err), err);
		goto out;
	}

	err = nvs_commit(nvram);
	if (err != ESP_OK) {
		Printf("nvs_commit:%s(%X)\n", esp_err_to_name(err), err);
		goto out;
	}
	ret = 0;

	out: nvs_close(nvram);
	return ret;
}

int nvram_get_data(char *name, void *data, int *size) {
	int ret = -1;
	nvs_handle_t nvram;
	esp_err_t err = nvs_open("nvram", NVS_READONLY, &nvram);
	if (err != ESP_OK) {
		Printf("nvs_open:%s(%X)\n", esp_err_to_name(err), err);
		return -1;
	}
	err = nvs_get_blob(nvram, name, data, (size_t*) size);
	if (err != ESP_OK) {
		Printf("nvs_get_blob %s:%s(%X)\n", name, esp_err_to_name(err), err);
		goto out;
	}
	ret = 0;

	out: nvs_close(nvram);
	return ret;
}

void save(void) {
	nvram_set_data("store", &mvar.store, sizeof(mvar.store));
}

void save_cal(void) {
	nvram_set_data("cal", &mvar.cal, sizeof(mvar.cal));
}

void save_count(void) {
	nvram_set_data("count", &mvar.count, sizeof(mvar.count));
}

void esp_print_tasks(void)
{
    char *pbuffer = (char *)calloc(1, 2048);
    printf("--------------- heap:%lu ---------------------\n", esp_get_free_heap_size());
    vTaskGetRunTimeStats(pbuffer);
    printf("%s", pbuffer);
    printf("----------------------------------------------\n");
    free(pbuffer);
}

void test_task(void *param)
{
    while(1) {

        esp_print_tasks();
        // Example of nvs_get_stats() to get the number of used entries and free entries:
        nvs_stats_t nvs_stats;
        nvs_get_stats(NULL, &nvs_stats);
        /*printf("Count: UsedEntries = (%d), FreeEntries = (%d), AllEntries = (%d)\n",
        		nvs_stats.used_entries, nvs_stats.free_entries, nvs_stats.total_entries);*/

        // Example of nvs_get_used_entry_count() to get amount of all key-value pairs in one namespace:
        nvs_handle_t handle;
        nvs_open("count", NVS_READWRITE, &handle);
        size_t used_entries;
        size_t total_entries_namespace=0;
        if(nvs_get_used_entry_count(handle, &used_entries) == ESP_OK){
            // the total number of entries occupied by the namespace
            total_entries_namespace = used_entries + 1;
        }
        printf("Count: UsedEntries = (%d), FreeEntries = (%d), AllEntries = (%d),count:(%d), sizeof(mvar.count):%d, sizeof(mvar.store):%d, sizeof(mvar.cal):%d\n",
                nvs_stats.used_entries, nvs_stats.free_entries, nvs_stats.total_entries,total_entries_namespace,sizeof(mvar.count),sizeof(mvar.store),sizeof(mvar.cal));

        vTaskDelay(10000);}
}

void app_main(void) {
	ESP_ERROR_CHECK(nvs_flash_init());					//初始化nvs存储
	ESP_ERROR_CHECK(esp_event_loop_create_default());

	struct timeval tv = { 0 };
	tv.tv_sec = 0;
	settimeofday(&tv, NULL);

	int size = sizeof(mvar.store);
	if (nvram_get_data("store", &mvar.store, &size) != ESP_OK		//读取配置信息
			|| size != sizeof(mvar.store)) {
		Printf("set defaults config.\n");
		mvar.store = defaults1;
	}

	size = sizeof(mvar.cal);
	if (nvram_get_data("cal", &mvar.cal, &size) != ESP_OK			//读取校准数据
			|| size != sizeof(mvar.cal)) {
		Printf("set defaults cal.\n");
		for (int i = 0; i < ASIZE(mvar.cal.volt); i++) {
			mvar.cal.volt[i].val = 1.0;
		}
		for (int i = 0; i < ASIZE(mvar.cal.curt); i++) {
			mvar.cal.curt[i].val = 1.0;
		}
	}

	size = sizeof(mvar.count);
	if (nvram_get_data("count", &mvar.count, &size) != ESP_OK		//读取累计记录数据
			|| size != sizeof(mvar.count)) {
		Printf("set defaults count.\n");
		mvar.count=defaults2;
		}

	init_timers_cpu();
	key_init();

	ina228_init(0);
	oled_init();

#ifdef CONFIG_IDF_TARGET_ESP32C3
	xTaskCreate(ina228_task, "ina228_task", 2048, NULL, 5, NULL);
	xTaskCreate(oled_task, "oled_task", 2048, NULL, 3, NULL);
	printf("oled_runing...\n");
	//xTaskCreate(test_task, "test_task", 2048, NULL, 5, NULL);		//打印CPU时间占用

#else
    setup_timer(&mvar.ina228_timer, ina228_timer_fun, 0);
    mod_timer(&mvar.ina228_timer, jiffies+50);
    setup_timer(&mvar.oled_timer, oled_timer_fun, 0);
    mod_timer(&mvar.oled_timer, jiffies+50);
#endif

	key_register_fun(keyNumSet, key_handler_fun);
	key_register_fun(keyNumLeft, key_handler_fun);
	key_register_fun(keyNumRight, key_handler_fun);

	setup_timer(&mvar.show_timer, show_timer_fun, 0);
	mod_timer(&mvar.show_timer, jiffies + 100);

	setup_timer(&mvar.elec_timer, elec_timer_fun, 0);
	mod_timer(&mvar.elec_timer, jiffies + HZ);

	mvar.view = main_views[mvar.store.main];
	while (1) {
		run_timers();
		vTaskDelay(1);
	}
}
